package bueu.bexl;

import java.util.ArrayList;

import java.util.List;

public abstract class ReferenceExpr extends WithNextExpr {

	protected final boolean ofContext;

	public ReferenceExpr(BexlExpr next, boolean ofContext) {
		super(!ofContext, next);
		this.ofContext = ofContext;
	}
	
	public final void setValue(final Object root, final Object value) {
		eval(Bexl.DEFAULT_CTX, root, true, value);
	}
	
	public final void setValue(final BexlCtx ctx, final Object value) {
		eval(ctx, ctx.getRoot(), true, value);
	}

	public final void setValue(final BexlCtx ctx, final Object root, final Object value) {
		eval(ctx, root, true, value);
	}
	
	@Override
	protected final Object eval(final BexlCtx ctx, final Object current, final boolean set,
			final Object newValue) throws BexlException {
		final ArrayList<Object> result = new ArrayList<Object>();
		
		if (this.ofContext) {
			eval(ctx, ctx, set, newValue, result);
		} else {
			final Object[] array = toArray(current);
			final int length = array.length;
			
			for (int i = 0; i < length; i++) {
				eval(ctx, array[i], set, newValue, result);
			}
		}
		
		return result.toArray();
	}

	protected abstract void eval(final BexlCtx ctx, final Object current, final boolean set,
			final Object newValue, final List<Object> result) throws BexlException;
	
	protected final void processNext(final BexlExpr next, final BexlCtx ctx, final Object current, final boolean set,
			final Object newValue, final List<Object> result) {

		if (current != null) {
			if (next != null) {
				((ReferenceExpr) next).eval(ctx, current, set, newValue, result);
			} else {
				result.add(current);
			}
		}
	}
	
	protected final void toStringNext(final StringBuilder sb) {
		final BexlExpr next = getNext();
		
		if (next != null) {
			if (!(next instanceof FilterExpr)) {
				sb.append(".");
			}
			
			sb.append(next);
		}
	}
}
